package com.boe.hbd.client.service.support;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.util.Log;

import com.boe.hbd.client.service.LocationService;

/**
 * This class should be initialized inside the main activity looper
 * 
 * @author jafu
 * 
 */
public class GpsBasedLocationService implements LocationService {

	private static final String TAG = "GpsBasedLocationService";

	private static final long TEN_SECONDS = 1000 ;
	private Context context = null;
	private Location location = null;
	private Object lock = new Object();
	private LocationManager locationManager = null;
	private LocationListener gpsListener = null;
	private LocationListener netListener = null;

	public void initialize(Context context) {
		this.context = context;
		locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
		// GPS: each 10 seconds get the location
		gpsListener = new LocationListener() {
			public void onLocationChanged(Location location) {
				GpsBasedLocationService.this.onLocationChanged(location);
			}

			public void onStatusChanged(String provider, int status, Bundle extras) {
				GpsBasedLocationService.this.onStatusChanged(provider, status, extras);
			}

			public void onProviderEnabled(String provider) {
				GpsBasedLocationService.this.onProviderEnabled(provider);
			}

			public void onProviderDisabled(String provider) {
				GpsBasedLocationService.this.onProviderDisabled(provider);
			}
		};
		netListener = new LocationListener() {
			public void onLocationChanged(Location location) {
				GpsBasedLocationService.this.onLocationChanged(location);
			}

			public void onStatusChanged(String provider, int status, Bundle extras) {
				GpsBasedLocationService.this.onStatusChanged(provider, status, extras);
			}

			public void onProviderEnabled(String provider) {
				GpsBasedLocationService.this.onProviderEnabled(provider);
			}

			public void onProviderDisabled(String provider) {
				GpsBasedLocationService.this.onProviderDisabled(provider);
			}
		};
	}
	 
	public void watchLocationUpdates() {
		// NETWORK: each 20 seconds, refresh the location
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TEN_SECONDS, 0, gpsListener);
		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TEN_SECONDS, 0, netListener);
	}

	public void destroy(Context context) {
		stopWatchLocationUpdates();
	}

	public void pause(Context context) {
    }

	public void resume(Context context) {
    }
	
	public void stopWatchLocationUpdates() {
		locationManager.removeUpdates(netListener);
		locationManager.removeUpdates(gpsListener);
	}

	public Location getLocation() {
		synchronized (lock) {
			if (location == null) {
				location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
			}
			if (location == null) {
				location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			}
			return location;
		}
	}

	public boolean isInitialized() {
		return context != null;
	}

	public void onLocationChanged(Location location) {
		Log.i(TAG, location.toString());
		synchronized (lock) {
			// when we don't have previous location or previous location comes from network or current location comes from GPS we'll update the location
			if (this.location == null || LocationManager.NETWORK_PROVIDER.equals(this.location.getProvider()) || LocationManager.GPS_PROVIDER.equals(location)) {
				this.location = location;
			}
			// if the previous location is old than 30 seconds, we also update it
			else if ((location.getTime() - this.location.getTime()) > TEN_SECONDS * 3) {
				this.location = location;
			}
		}
	}

	public void onStatusChanged(String provider, int status, Bundle extras) {
		String statusStr = "" ;
		switch (status ) {
		case LocationProvider.AVAILABLE : {
			statusStr = "AVAILABLE" ;
			
		} break ;
		case LocationProvider.OUT_OF_SERVICE : {
			statusStr = "OUT_OF_SERVICE" ;			
		} break ;
		case LocationProvider.TEMPORARILY_UNAVAILABLE : {
			statusStr = "TEMPORARILY_UNAVAILABLE" ;			
		} break ;
		}
		Log.i(TAG, provider + "[" + statusStr + "]");
	}

	public void onProviderEnabled(String provider) {
		Log.i(TAG, provider + "[ON]");
	}

	public void onProviderDisabled(String provider) {
		Log.i(TAG, provider + "[OFF]");
	}
}
